﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.IO;
using GRTVPluginConsole.Utils;
using System.Diagnostics;
using System.Windows.Forms;
using System.Net;
using System.Runtime.Serialization.Json;
using GRTVPluginConsole.JSON.playerFile;

namespace GRTVPluginConsole.Listener.Processors
{
    class PluginEnvironmentMessageProcessor
    {
        GRTVPluginConsole.Listener.PluginListenerThread.WeatherDataReceived callback;
        byte[] data;
        string profile;
        string profilePath;
        string gdbFilename;
        string aiwFilename;
        public PluginEnvironmentMessageProcessor(IPEndPoint ep, byte[] _data, GRTVPluginConsole.Listener.PluginListenerThread.WeatherDataReceived callback)
        {
            data = _data;
            this.callback = callback;
        }

        private string getString(byte[] data, int offset, int length)
        {
            for (int i = 0; i < length; i++)
            {
                if (data[offset + i] == 0)
                {
                    return Encoding.ASCII.GetString(data, offset, i);
                }
            }
            return Encoding.ASCII.GetString(data, offset, length);
        }
        public void ThreadLoop(Object threadContext)
        {

            string str = getString(data, 1, data.Length - 1);

                try
                {
                    int i = str.LastIndexOf("\\");
                    str = str.Substring(0, i);
                    i = str.LastIndexOf("\\");
                    profile = str.Substring(i + 1);
                    profilePath = str;

                }
                catch (Exception e)
                {
                    setMessage("Cannot retrieve profile path from the TVplugin trame: " + str);
                    return;
                }

                bool coordRetrievedFromIni = false;
                try
                {
                    // find PLR
                    string plrPath = profilePath + "\\" + profile + ".PLR";
                    string jsonPath = profilePath + "\\" + profile + ".JSON";
                    bool havePLR = File.Exists(plrPath);
                    bool haveJSON = File.Exists(jsonPath); ;
                    if (!havePLR && !haveJSON)
                    {
                        setMessage("Cannot find " + profile + ".PLR or" + profile + ".JSON file in " + profilePath);
                        return;
                    }
                    // get scene file from PLR
                    string scnPath = "";
                    if (havePLR)
                    {
                        IniFile plrFile = new IniFile(plrPath);
                        scnPath = plrFile.IniReadValue(" SCENE ", "Scene File");
                        if (scnPath.StartsWith("\""))
                        {
                            scnPath = scnPath.Substring(1, scnPath.Length - 1);
                        }
                        if (scnPath.EndsWith("\""))
                        {
                            scnPath = scnPath.Substring(0, scnPath.Length - 1);
                        }
                    }
                    else
                    {
                        try
                        {
                            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(PlayerFile));
                            using (FileStream fs = new FileStream(jsonPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                            {
                                PlayerFile obj = (PlayerFile)ser.ReadObject(fs);
                                scnPath = obj.sceneSection.filepath;
                            }
                        }
                        catch (Exception exjson)
                        {
                            setMessage("Cannot parse JSON " + jsonPath + ": " + exjson.Message);
                            return;
                        }
                    }
                    // check that output directory exists (else create it)
                    Directory.CreateDirectory(Program.configuration.gdbExtractPath);

                    // find GDB name
                    int iBS = scnPath.LastIndexOf("\\");
                    string gdbName = scnPath.Substring(iBS + 1);
                    gdbName = gdbName.Substring(0, gdbName.Length - 3) + "GDB";
                    gdbFilename = gdbName;
                    string aiwName = gdbName.Substring(0, gdbName.Length - 3) + "AIW";
                    aiwFilename = aiwName;

                    if (callback != null)
                    {
                        callback(this, 0, gdbFilename);
                    }

                    string iniLat = Program.configuration.iniTrackFile.IniReadValue(gdbName, "latitude");
                    string iniLon = Program.configuration.iniTrackFile.IniReadValue(gdbName, "longitude");
                    if (!"".Equals(iniLat) && !"".Equals(iniLon))
                    {
                        NumberStyles style = NumberStyles.Float;
                        CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");

                        decimal number;
                        if (Decimal.TryParse(iniLat, style, culture, out number))
                        {
                            Program.configuration.realtimeConfig.ownLatitude = (double)number;
                            // plugin.lattitude = 50.91;
                        }
                        else
                        {
                            setMessage("Error parsing latitude from track ini file for track : " + gdbName);
                            return;
                        }
                        if (Decimal.TryParse(iniLon, style, culture, out number))
                        {
                            Program.configuration.realtimeConfig.ownLongitude = (double)number;
                            //  plugin.longitude = 15.48;
                        }
                        else
                        {
                            setMessage("Error parsing longitude from track ini file for track : " + gdbName);
                            return;
                        }
                        coordRetrievedFromIni = true;
                    }

                    if (/*!plugin.overrideGDB &&*/ File.Exists(Program.configuration.gdbExtractPath + "\\" + gdbName))
                    {
                        CollectGdbData(coordRetrievedFromIni);
                        return;
                    }

                    // find ModMgr.exe file
                    string modMgrPath = Program.configuration.corePath + "\\Bin32\\ModMgr.exe";
                    if (!File.Exists(modMgrPath))
                    {
                        if (!coordRetrievedFromIni)
                        {
                            setMessage("Cannot find ModMgr.exe file : " + modMgrPath);
                        } else {
                            okLatLongCollected();
                        }
                        return;
                    }

                    // parse all MAS files
                    string masDir = scnPath.Substring(0, iBS);
                    string[] file = Directory.GetFiles(masDir, "*.mAs");
                    if (file.Length == 0)
                    {
                        if (!coordRetrievedFromIni)
                        {
                            setMessage("No MAS file found under : " + masDir);
                        }
                        else
                        {
                            okLatLongCollected();
                        }
                        return;
                    }

                    string modMgrCmd = "\"" + modMgrPath + "\"";
                    for (int iMas = 0; iMas < file.Length; iMas++)
                    {
                        string masPath = file[iMas];
                        string modMgrArgs = "-x\"" + masPath + "\" " + gdbName + (/*plugin.extractAIW */true? (" " + aiwName) : "") + " -o\"" + Program.configuration.gdbExtractPath + "\"";


                        var process = Process.Start(modMgrCmd, modMgrArgs);
                        process.WaitForExit();
                        int retCode = process.ExitCode;
                        if (retCode != 0)
                        {
                            if (!coordRetrievedFromIni)
                            {
                                setMessage("Error extracted GDB, ModMgr.exe exited with code: " + retCode);
                            }
                            else
                            {
                                okLatLongCollected();
                            }
                            return;
                        }

                        //if (plugin.extractAIW)
                        //{
                        //    try
                        //    {
                        //        string aiwName = gdbName.Substring(0, gdbName.Length - 3) + "AIW";
                        //        modMgrArgs = "-x\"" + masPath + "\" " + aiwName + " -o\"" + Program.configuration.gdbExtractPath + "\"";
                        //        process = Process.Start(modMgrCmd, modMgrArgs);
                        //    }
                        //    catch (Exception eaiw)
                        //    {
                        //        // as it is only a bonus, i don't want to display an error
                        //    }
                        //}
                        if (File.Exists(Program.configuration.gdbExtractPath + "\\" + gdbName))
                        {
                            break;
                        }
                    }

                    // extract AIW (bonus for TrackMap plugin)
                    if (File.Exists(Program.configuration.gdbExtractPath + "\\" + gdbName))
                    {
                        CollectGdbData(coordRetrievedFromIni);
                    }
                    else
                    {
                        if (!coordRetrievedFromIni)
                        {
                            setMessage("GDB file not extracted, file not found: " + Program.configuration.gdbExtractPath + "\\" + gdbName);
                        }
                        else
                        {
                            okLatLongCollected();
                        }
                        return;
                    }

                }
                catch (Exception ex)
                {
                    if (!coordRetrievedFromIni)
                    {
                        setMessage("Cannot extract GDB file, reason is : " + ex.Message);
                    }
                    else
                    {
                        okLatLongCollected();
                    }
                    return;
                }


        }
        private void setMessage(string str)
        {
            if (callback != null)
            {
                callback(this, 1, str);
            }
        }
        private void CollectGdbData(bool coordRetrievedFromIni)
        {
            string line;
            NumberStyles style = NumberStyles.Float;
            CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
            // Read the file and display it line by line.
            System.IO.StreamReader file =
               new System.IO.StreamReader(Program.configuration.gdbExtractPath + "\\" + gdbFilename);
            while ((line = file.ReadLine()) != null)
            {
                if (line.Contains("TrackName"))
                {
                    //plugin.trackName = line.Substring(line.IndexOf("=") + 1).Trim();
                }
                else if (line.Contains("Location"))
                {
                    //plugin.location = line.Substring(line.IndexOf("=") + 1).Trim();
                }
                else if (!coordRetrievedFromIni && line.Contains("Latitude"))
                {
                    string lat = line.Substring(line.IndexOf("=") + 1).Trim();
                    if (lat.IndexOf(" ") > -1)
                    {
                        lat = lat.Substring(0, lat.IndexOf(" "));
                    }
                    decimal number;
                    if (Decimal.TryParse(lat, style, culture, out number))
                    {
                        Program.configuration.realtimeConfig.ownLatitude = (double)number;
                        // plugin.lattitude = 50.91;
                    }
                    else
                    {
                        Program.configuration.realtimeConfig.ownLatitude = 360;
                        setMessage("Cannot parse latitude from GDB: " + lat);
                    }
                }
                else if (!coordRetrievedFromIni && line.Contains("Longitude"))
                {
                    string lon = line.Substring(line.IndexOf("=") + 1).Trim();
                    if (lon.IndexOf(" ") > -1)
                    {
                        lon = lon.Substring(0, lon.IndexOf(" "));
                    }
                    decimal number;
                    if (Decimal.TryParse(lon, style, culture, out number))
                    {
                        Program.configuration.realtimeConfig.ownLongitude = (double)number;
                        //  plugin.longitude = 15.48;
                    }
                    else
                    {
                        Program.configuration.realtimeConfig.ownLongitude = 360;
                        setMessage("Cannot parse longitude from GDB: " + lon);
                    }
                }
            }

            file.Close();

            okLatLongCollected();
        }

        private void okLatLongCollected()
        {
            if (callback != null)
            {
                callback(this, 2, null);
            }
        }
    }
}

